﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Sokoban_Solver
{
    class Point
    {
        public int row { get; set; }
        public int col { get; set; }
        public Point(int row, int col)
        {
            this.row = row;
            this.col = col;
        }
    }
    
    class Sokoban
    {
        public Point[] boxes { get; set; }
        public Point[] goals { get; set; }
        public Point player { get; set; }
        public Sokoban parent = null;
        public int melysegSzam;
        public int[,] map { get; set; }
        public int maxRow { get; set; }
        public int maxCol { get; set; }
        
        public void PointListabolPointTombbe(List<Point> lista, Point[] tomb)
        {
            for (int i = 0; i < lista.Count; i++)
                tomb[i] = lista[i];
        }
        public Sokoban(int maxRow, int maxCol, int[,] map, Point player, List<Point> boxes, List<Point> goals, int melyseg, Sokoban parent)
        {
            this.maxRow = maxRow;
            this.maxCol = maxCol;
            this.map = new int[maxRow, maxCol];
            this.map = map;
            this.boxes = new Point[boxes.Count];
            PointListabolPointTombbe(boxes, this.boxes);
            this.goals = new Point[goals.Count];
            PointListabolPointTombbe(goals, this.goals);
            this.player = player;
            this.melysegSzam = melyseg;
            this.parent = parent;
        }
        public Sokoban()
        {

        }
        public Sokoban(int maxRow, int maxCol, int[,] map, Point player, Point[] boxes, Point[] goals, int melyseg, Sokoban parent)
        {
            this.maxRow = maxRow;
            this.maxCol = maxCol;
            this.map = new int[maxRow, maxCol];
            this.map = map;
            this.boxes = boxes;
            this.goals = goals;
            this.player = player;
            this.melysegSzam = melyseg;
            this.parent = parent;
        }        
        public bool VanOttDoboz(int row, int col)
        {
            for (int i = 0; i < boxes.Length; i++)
                if ((boxes[i].row == row) && (boxes[i].col == col))
                    return true;
            return false;
        }
        public int MelyikDobozVanOtt(int row, int col)
        {
            int index = 0;
            while (!((boxes[index].row == row) && (boxes[index].col == col)))
                index++;
            return index;
        }
        public bool VanOttCel(int row, int col)
        {
            for (int i = 0; i < goals.Length; i++)
                if ((goals[i].row == row) && (goals[i].col == col))
                    return true;
            return false;
        }
        public void DrawMap()
        {
            char[] kar = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T' };
            Console.Write("    ");
            for (int col = 0; col < maxCol; col++)
                Console.Write(kar[col]);
            Console.WriteLine();
            for (int row = 0; row < maxRow; row++)
            {
                Console.Write("{0,3} ",row);
                for (int col = 0; col < maxCol; col++)
                {
                    string s = null;
                    if (map[row, col] == 0)
                        s = ":";
                    else
                        s = " ";
                    if ((row == player.row) && (col == player.col))
                        s = "P";
                    if (VanOttCel(row, col))
                        s = "O";
                    if (VanOttDoboz(row, col))
                        s = "B";
                    if (VanOttDoboz(row, col) && VanOttCel(row, col))
                        s = "X";
                    Console.Write(s);
                }
                Console.WriteLine();
            }
            Console.WriteLine();
        }
        public bool GoalState()
        {
            for (int i = 0; i < boxes.Length; i++)
                if (!VanOttCel(boxes[i].row, boxes[i].col))
                    return false;
            return true;
        }
        public bool Jobbra()
        {
            if (map[player.row, player.col + 1] == 0)
                return false;
            if ((map[player.row, player.col + 1] == 1) && (!VanOttDoboz(player.row, player.col + 1)))
            {
                player.col++;
                return true;
            }
            if (VanOttDoboz(player.row,player.col+1))
            {
                if ((VanOttDoboz(player.row, player.col + 2)) || (map[player.row, player.col + 2] == 0))
                    return false;
                else
                {
                    int box = MelyikDobozVanOtt(player.row, player.col + 1);
                    boxes[box].col++;
                    player.col++;
                    return true;
                }
            }
            return false;
        }
        public bool Balra()
        {
            if (map[player.row, player.col - 1] == 0)
                return false;
            if ((map[player.row, player.col - 1] == 1) && (!VanOttDoboz(player.row, player.col - 1)))
            {
                player.col--;
                return true;
            }
            if (VanOttDoboz(player.row, player.col - 1))
            {
                if ((VanOttDoboz(player.row, player.col - 2)) || (map[player.row, player.col - 2] == 0))
                    return false;
                else
                {
                    int box = MelyikDobozVanOtt(player.row, player.col - 1);
                    boxes[box].col--;
                    player.col--;
                    return true;
                }
            }
            return false;
        }
        public bool Fel()
        {
            if (map[player.row -1, player.col] == 0)
                return false;
            if ((map[player.row -1, player.col] == 1) && (!VanOttDoboz(player.row-1, player.col)))
            {
                player.row--;
                return true;
            }
            if (VanOttDoboz(player.row -1, player.col))
            {
                if ((VanOttDoboz(player.row-2, player.col)) || (map[player.row-2, player.col] == 0))
                    return false;
                else
                {
                    int box = MelyikDobozVanOtt(player.row-1, player.col);
                    boxes[box].row--;
                    player.row--;
                    return true;
                }
            }
            return false;
        }
        public bool Le()
        {
            if (map[player.row + 1, player.col] == 0)
                return false;
            if ((map[player.row + 1, player.col] == 1) && (!VanOttDoboz(player.row + 1, player.col)))
            {
                player.row++;
                return true;
            }
            if (VanOttDoboz(player.row + 1, player.col))
            {
                if ((VanOttDoboz(player.row + 2, player.col)) || (map[player.row + 2, player.col] == 0))
                    return false;
                else
                {
                    int box = MelyikDobozVanOtt(player.row + 1, player.col);
                    boxes[box].row++;
                    player.row++;
                    return true;
                }
            }
            return false;
        }
    }
}
